iT邦幫忙

0

[Day3]檔案批次整理器:自動依月份與副檔名歸檔

  • 分享至 

  • xImage
  •  

今天要做什麼
把一個資料夾(例如 Download)裡的檔案,自動整理到:

目標資料夾/
  2025-07/
    pdf/
    jpg/
  2025-08/
    docx/
    png/

預設 move(搬移,保留時間戳與檔名)
可用 --mode copy 改成複製
可用 --dry 先試跑不動檔

會用到
pathlib 檔案系統
shutil 複製/搬移
datetime 取檔案時間
argparse 命令列參數

程式碼(organize.py)
把下面存成 organize.py 放在你的 project 資料夾。

from pathlib import Path
import argparse, shutil, datetime as dt, sys, os

def month_bucket(p: Path) -> str:
    """依檔案最後修改時間決定月份資料夾名稱,例如 2025-09"""
    ts = dt.datetime.fromtimestamp(p.stat().st_mtime)
    return f"{ts:%Y-%m}"

def is_hidden(p: Path) -> bool:
    # 排除隱藏/系統檔(跨平台簡易判斷)
    name = p.name
    if name.startswith("."):  # mac/Linux 隱藏檔
        return True
    # Windows: 用 FILE_ATTRIBUTE_HIDDEN(簡化:跳過常見 OneDrive 暫存)
    return name in ("desktop.ini", "Thumbs.db")

def unique_target_path(target_dir: Path, name: str) -> Path:
    """避免同名覆蓋:若已存在,加入 (1), (2)..."""
    base, dot, ext = name.partition(".")
    candidate = target_dir / name
    i = 1
    while candidate.exists():
        candidate = target_dir / (f"{base} ({i})" + (dot + ext if dot else ""))
        i += 1
    return candidate

def organize(src: Path, dst: Path, mode: str, dry: bool):
    if not src.exists():
        sys.exit(f"來源不存在:{src}")
    if not src.is_dir():
        sys.exit("來源必須是資料夾")

    count = 0
    for f in src.rglob("*"):
        if not f.is_file():
            continue
        if is_hidden(f):
            continue

        month = month_bucket(f)
        ext = f.suffix.lower().lstrip(".") or "noext"
        target_dir = dst / month / ext
        target_dir.mkdir(parents=True, exist_ok=True)

        target_path = unique_target_path(target_dir, f.name)

        rel = f.relative_to(src)
        if dry:
            print(f"[DRY] {rel}  ->  {target_path.relative_to(dst)}")
        else:
            if mode == "move":
                shutil.move(str(f), target_path)
            else:
                shutil.copy2(str(f), target_path)
            count += 1

    if dry:
        print("(乾跑模式)不做任何實際搬移/複製。")
    else:
        print(f"✅ 完成,處理檔案數:{count}")

def main():
    ap = argparse.ArgumentParser(description="檔案批次整理器:依月份與副檔名分類")
    ap.add_argument("--src", required=True, help="來源資料夾")
    ap.add_argument("--dst", required=True, help="目標資料夾")
    ap.add_argument("--mode", choices=["move", "copy"], default="move", help="move=搬移(預設),copy=複製")
    ap.add_argument("--dry", action="store_true", help="乾跑模式(只顯示要做什麼,不動檔)")
    args = ap.parse_args()

    src = Path(args.src).expanduser()
    dst = Path(args.dst).expanduser()
    organize(src, dst, args.mode, args.dry)

if __name__ == "__main__":
    main()

執行範例
先試跑(不動檔)python organize.py --src "C:\Users\anna4\Downloads" --dst "C:\Users\anna4\Projects\Media" --dry
真的搬移

python organize.py --src "C:\Users\anna4\Downloads" --dst "C:\Users\anna4\Projects\Media"

改成複製
python organize.py --src "C:\Users\anna4\Downloads" --dst "C:\Users\anna4\Projects\Media" --mode copy

實作:
https://ithelp.ithome.com.tw/upload/images/20250923/2016936854G9IbujoQ.png

今日重點
pathlib 讓走訪檔案結構更直覺
依stat().st_mtime 取得最後修改時間分桶
碰到同名檔,動態加 (1)(2)… 避免覆蓋
先 dry-run 再正式動作,安全不踩雷

明天Day 4我們會做一個小型爬蟲,抓一個公開網站的標題與連結(含合法爬蟲禮節與限速)。


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言